
#define FRAME_QUEUE_SIZE 10

typedef struct Frame {
	AVFrame *frame;
	AVSubtitle sub;
	double pts;		//显示时间
	double duration;	//当前frame帧时长
	int width;
	int height;
	int format;
	int uploaded;
}Frame;

class FrameQueue {
	public:
		FrameQueue(int max_size, int keep_last);
		virtual ~FrameQueue();

		void start();

		void abort();

		Frame *currentFrame();

		Frame *nextFrame();

		Frame *lastFrame();

		Frame *peekWritable();

		void pushFrame();

		void popFrame();

		void flush();

		int getFrameSize();

		int getShowIndex() const;

	private:
		void unrefFrame(Frame *vp);
	private:
		Mutex mMutex;
		Condition mCondition;
		int abort_request;
		Frame queue[FRAME_QUEUE_SIZE];
		int rindex;
		int windex;
		int size;
		int max_size;
		int keep_last;
		int show_index;
};

FrameQueue::FrameQueue(int max_size, int keep_last) {
	memset(queue, 0, sizeof(Frame) *FRAME_QUEUE_SIZE);
	this->max_size = FFMIN(max_size, FRAME_QUEUE_SIZE);		//去较小的值,max_size就是queue的长度，queue是数组实现的循环队列
	this->keep_last = (keep_last != 0);
	for(int i = 0; i < this->max_size; i++){
		queue[i].frame = av_frame_alloc();
	}
	abort_request = 1;
	rindex = 0;		//取数据位置
	windex = 0;		//放数据位置
	size = 0;		//存放数据长度
	show_index = 0;		//不知道
}

FrameQueue::~FrameQueue(){
	for(int i = 0; i< max_size; i++){
		Frame *vp = queue[i];
		unrefFrame(vp);
		av_frame_free(&vp->frame);
	}
}

void FrameQueue::start() {
	mMutex.lock();
	abort_request = 0;
	mCondition.signal();
	mMutex.unlock();
}

void FrameQueue::abort() {
	mMutex.lock();
	abort_request = 1;
	mCondition.signal();
	mMutex.unlock();
}


Frame *FrameQueue::currentFrame() {
	return &queue[(rindex+show_index) % max_size];
}

Frame *FrameQueue::nextFrame() {
	return &queue[(rindex+show_index+1) % max_size];
}

Frame *FrameQueue::lastFrame() {
	return &queue[rindex];
}

//存放解压后的视频数据
Frame *FrameQueue::peekWritable() {
	mMutex.lock();
	while(!abort_request && size > max_size){
		mCondition.wait(mMutex);
	}
	mMutex.unlock();
	if(abort_request){
		return NULL;
	}
	return &queue[windex];
}

//入栈加1，这里没有对大于max_size处理杀死因为调用次方法之前会先调用peekWiteable这个方法里面对大于max_size做了处理
void FrameQueue::pushFrame() {
	if(++windex == max_size){
		windex = 0;
	}
	mMutex.lock();
	size++;
	mCondition.signal();
	mMutex.unlokc();
}

void FrameQueue:popFrame() {
	if(keep_last && !show_index) {
		show_index = 1;
		return;
	}
	unrefFrame(&queue[rindex]);
	if(++rindex == max_size) {
		rindex = 0;
	}
	mMutex.lock();
	size--;
	mCondition.signal();
	mMutex.unlock();
}

void FrameQueue::flush() {
	while(getFrameSize() > 0 ){
		popFrame();
	}
}

int FrameQueue::getFrameSize() {
	reutn size - show_index;
}

void FrameQueue::unrefFrame(Frame *vp){
	av_frame_unref(vp->frame);
	avsubtitle_free(&vp->sub);
}

int FrameQueue::getShowIndex() const {
	return show_index;
}
